package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

type Job struct {
	id       int
	randomno int
}

type Result struct {
	job Job
	sumofdigits int
}

var jobs = make(chan Job, 10)
var results = make(chan Result, 10)

func digits(number int) int {
	sum := 0
	no := number
	for no != 0 {
		digit := no % 10
		sum += digit
		no /= 10
	}
	// 模拟方法执行耗时
	time.Sleep(1 * time.Second)
	return sum
}

// 工作协程（worker go routine） 会监听缓冲信道job里更新的作业
func worker(wg *sync.WaitGroup) {
	// jobs缓冲通道没有关闭，这个for就会一直存在，直到jobs关闭
	for job := range jobs {
		output := Result{job, digits(job.randomno)}
		results <- output
		fmt.Println("存：", job)
	}
	wg.Done()
}

// 创建go协程的工作池
func createWorkerPool(noOfWorkers int) {
	var wg sync.WaitGroup
	for i := 0; i < noOfWorkers; i++ {
		wg.Add(1)
		go worker(&wg)
	}
	wg.Wait()
	close(results)
}

// 分配工作
func allocate(noOfJobs int) {
	for i := 0; i < noOfJobs; i++ {
		randomno := rand.Intn(999)
		job := Job{i, randomno}
		jobs <- job
		fmt.Println("分配：", job)
	}
	close(jobs)

}

func result(done chan bool) {
	for result := range results{
		fmt.Printf("Result(job(id=%d, randomno=%d), sumofdigits=%d) \n", result.job.id, result.job.randomno, result.sumofdigits)
	}
	done <- true
}

func main() {
	startTime := time.Now()
	fmt.Println(startTime)
	noOfJobs := 50
	go allocate(noOfJobs)
	fmt.Println("after allocate()")
	done := make(chan bool)
	go result(done)
	fmt.Println("after result()")
	noOfWorkers := 20
	createWorkerPool(noOfWorkers)
	fmt.Println("after createWorkerPool()")
	<- done
	endTime := time.Now()
	diff := endTime.Sub(startTime)
	fmt.Printf("总耗时: %f (秒)", diff.Seconds())
}
